from typing import Optional, AsyncGenerator

from neo4j import AsyncDriver, AsyncGraphDatabase, TrustAll, TrustSystemCAs, TrustCustomCAs
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.pool import QueuePool
from .config import settings
from redis.asyncio import Redis

# 1. 创建异步数据库引擎 - 核心接口，连接池在此管理
# echo=True 在开发时显示SQL语句，生产环境应设为False
# poolclass=QueuePool 使用连接池，复用连接，提升性能
# pool_size, max_overflow 控制连接池容量，根据实际情况调整
engine = create_async_engine(
    settings.DB_URI.unicode_string(), # 确保URL为字符串
    echo=settings.DEBUG,
    pool_size=settings.DB_POOL_SIZE,
    max_overflow=settings.DB_MAX_OVERFLOW,
    pool_timeout = settings.POOL_TIMEOUT,
    pool_pre_ping = settings.POOL_PRE_PING,
    future=True # 确保使用SQLAlchemy 2.0风格
)

# 2. 创建异步会话工厂
# `async_sessionmaker` 是一个用于创建AsyncSession的工厂
# autocommit=False, autoflush=False 是标准配置，确保事务控制权在我们自己手里
AsyncSessionLocal = async_sessionmaker(
    bind=engine,
    class_=AsyncSession,
    autocommit=False,
    autoflush=False,
    expire_on_commit=False, # 避免在异步环境中访问过期属性导致错误
)

# 3. 定义ORM模型基类
# 所有数据模型都应继承自此基类
class Base(DeclarativeBase):
    pass

# 4. 创建数据库表（可选，通常由Alembic迁移工具负责）
# async def create_tables():
#     async with engine.begin() as conn:
#         await conn.run_sync(Base.metadata.create_all)

# 5. 依赖注入函数 - 最重要的部分！
# 每个请求获取一个独立的数据库会话，请求处理完成后自动关闭
async def get_db() -> AsyncSession: # type: ignore
    """
    获取异步数据库会话的依赖项。
    在路由函数中通过 `db: AsyncSession = Depends(get_db)` 使用。
    注意：必须使用 `async with` 上下文管理器来确保会话正确关闭。
    """
    async with AsyncSessionLocal() as session:
        try:
            yield session # 将会话提供给请求使用
        finally:
            await session.close() # 确保会话最终被关闭，释放连接回连接池

_redis: Redis|None = None
async def get_redis() ->Redis:
    global _redis
    if _redis is None:
        _redis = Redis.from_url(
            str(settings.REDIS_URL),
            encoding = "utf-8",
            decode_responses = True
        )
    return _redis



_neo4j_driver: Optional[AsyncDriver] = None

# 将字符串配置转换为信任策略对象
trust_strategy = {
    "TRUST_ALL_CERTIFICATES": TrustAll(),
    "TRUST_SYSTEM_CA_SIGNED_CERTIFICATES": TrustSystemCAs(),
    "TRUST_CUSTOM_CA_SIGNED_CERTIFICATES": TrustCustomCAs()
}.get(settings.NEO4J_TRUST_STRATEGY, TrustAll())
async def get_neo4j_driver() -> AsyncDriver:
    """获取全局 Neo4j 异步驱动实例（单例模式）"""
    global _neo4j_driver
    if _neo4j_driver is None:
        try:
            uri = str(settings.NEO4J_URI)
            _neo4j_driver = AsyncGraphDatabase.driver(
                uri,
                auth=(settings.NEO4J_USER, settings.NEO4J_PASSWORD),
                max_connection_pool_size=settings.NEO4J_MAX_CONNECTION_POOL_SIZE,
                connection_timeout=settings.NEO4J_CONNECTION_TIMEOUT,
                encrypted=settings.NEO4J_ENCRYPTED,
                # trust_=settings.NEO4J_TRUST_STRATEGY,
                trusted_certificates= trust_strategy
            )
            # 验证连接
            await _neo4j_driver.verify_connectivity()
            print("✅ Neo4j 驱动连接成功")
        except Exception as e:
            print(f"❌ Neo4j 驱动连接失败: {e}")
            raise
    return _neo4j_driver

async def get_neo4j_session() -> AsyncGenerator[AsyncDriver, None]:
    """Neo4j 会话依赖注入函数"""
    driver = await get_neo4j_driver()
    try:
        yield driver
    finally:
        # 注意：这里不关闭驱动，驱动是全局单例
        pass

async def close_neo4j_driver():
    """关闭 Neo4j 驱动（用于应用关闭时清理）"""
    global _neo4j_driver
    if _neo4j_driver is not None:
        await _neo4j_driver.close()
        _neo4j_driver = None
        print("✅ Neo4j 驱动已关闭")

# 快捷方式：直接执行查询的依赖
async def get_neo4j_query_executor():
    """获取 Neo4j 查询执行器（快捷方式）"""
    return await get_neo4j_driver()
